package framework.eea;

import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.LinkedBlockingQueue;
import framework.eea.entity.EntityManager;
import framework.eea.exception.EEAException;
import framework.eea.gui.JFrameGameContainer;
import framework.eea.gui.Graphics;
import framework.eea.interfaces.Game;
import framework.eea.state.GameState;

/**
 *
 * @author Markus Schr&ouml;der
 */
public abstract class StateBasedGame implements Game {

    private Map<Integer, GameState> states;
    private GameState currentState;
    private JFrameGameContainer container;
    private String title;
    private Queue<KeyEvent> keyPressedQueue;
    private Queue<KeyEvent> keyReleasedQueue;
    
    public StateBasedGame(String name) {
        this.title = name;
        this.states = new HashMap<Integer, GameState>();
        this.currentState = null;
        this.keyPressedQueue = new LinkedBlockingQueue<KeyEvent>();
        this.keyReleasedQueue = new LinkedBlockingQueue<KeyEvent>();
    }
    
    
    //STATES
    
    public void addState(GameState state) throws EEAException {
        EntityManager.getInstance().addState(state.getID());
        states.put(state.getID(), state);
        state.init(container, this);
    }
    
    public int getStateCount() {
        return states.size();
    }

    public int getCurrentStateID() {
        return currentState.getID();
    }

    public GameState getCurrentState() {
        return currentState;
    }
    
    public GameState getState(int id) {
        return states.get(id);
    }

    public void enterState(int id) throws EEAException {
        getCurrentState().leave(container, this);
        
        GameState next = getState(id);
        next.enter(container, this);
        
        currentState = next;
    }
    
    public void quit() {
        container.stop();
    }
    
    // INIT UPDATE RENDER
    
    @Override
    public final void init(JFrameGameContainer gc) throws EEAException {
        this.container = gc;
        
        for(String ref : initImages()) {
            try {
                gc.loadImage(ref);
            } catch (IOException ex) {
                throw new EEAException(ex.getMessage(), ex);
            }
        }
        initGraphics(gc);
        initStatesList(gc);
        initServerClient(gc);
        
        
        if(!states.isEmpty()) {
            currentState = (GameState) states.values().toArray()[0];
            currentState.enter(container, this);
        }
    }
    
    public abstract void initServerClient(JFrameGameContainer gc) throws EEAException;
    
    public abstract void initStatesList(JFrameGameContainer gc) throws EEAException;
    
    public abstract String[] initImages();
    
    public abstract void initGraphics(JFrameGameContainer gc) throws EEAException;
    
    @Override
    public final void deinit(JFrameGameContainer gc) throws EEAException {
        deinitServerClient(gc);
    }
    
    public abstract void deinitServerClient(JFrameGameContainer gc) throws EEAException;
    
    
    // UPDATE RENDER
    
    @Override
    public void update(JFrameGameContainer gc, int delta) throws EEAException {
        getCurrentState().update(container, this, delta);
        
        getKeyPressedQueue().poll();
        getKeyReleasedQueue().poll();
    }

    @Override
    public void render(JFrameGameContainer gc, Graphics grphcs) throws EEAException {
        getCurrentState().render(container, this, grphcs);
    }

    
    //INPUT
    
    @Override
    public void keyTyped(KeyEvent ke) {}

    @Override
    public void keyPressed(KeyEvent ke) {
        getKeyPressedQueue().add(ke);
    }

    @Override
    public void keyReleased(KeyEvent ke) {
        getKeyReleasedQueue().add(ke);
    }
    
    @Override
    public void mouseClicked(MouseEvent me) {}

    @Override
    public void mousePressed(MouseEvent me) {}

    @Override
    public void mouseReleased(MouseEvent me) {}

    @Override
    public void mouseEntered(MouseEvent me) {}

    @Override
    public void mouseExited(MouseEvent me) {}
    
    @Override
    public void mouseDragged(MouseEvent me) {}

    @Override
    public void mouseMoved(MouseEvent me) {}
    
    //GETTER
    
    @Override
    public String getTitle() {
        return title;
    }

    /**
     * @return the keyPressedQueue
     */
    public Queue<KeyEvent> getKeyPressedQueue() {
        return keyPressedQueue;
    }

    /**
     * @return the keyReleasedQueue
     */
    public Queue<KeyEvent> getKeyReleasedQueue() {
        return keyReleasedQueue;
    }
}
